#include "personaje.h"

anim_t CPersonaje::animlist[ 21 ] = 
{
    // first, last, fps

    {   0,  39,  7 },   // STAND
    {  40,  45, 7 },   // RUN
    {  46,  53, 1 },   // ATTACK
    {  54,  57,  7 },   // PAIN_A
    {  58,  61,  7 },   // PAIN_B
    {  62,  65,  7 },   // PAIN_C
    {  66,  71,  7 },   // JUMP
    {  72,  83,  7 },   // FLIP
    {  84,  94,  7 },   // SALUTE
    {  95, 111, 10 },   // FALLBACK
    { 112, 122,  7 },   // WAVE
    { 123, 134,  6 },   // POINT
    { 135, 153, 10 },   // CROUCH_STAND
    { 154, 159,  7 },   // CROUCH_WALK
    { 160, 168, 20 },   // CROUCH_ATTACK
    { 196, 172,  7 },   // CROUCH_PAIN
    { 173, 177,  5 },   // CROUCH_DEATH
    { 178, 183,  7 },   // DEATH_FALLBACK
    { 184, 189,  7 },   // DEATH_FALLFORWARD
    { 190, 197,  7 },   // DEATH_FALLBACKSLOW
    { 198, 198,  5 },   // BOOM
};

anim_t CPersonaje::mis_animlist[ NUM_ANIMACIONES ] = 
{
    // first, last, fps

    {   0,  39,  9 },   // NORMAL
    {  40,  45, 7  },    // CORRER
    {  46,  53, 10 },   // ATAQUE
    {  54,  59,  7 },   // SALTO
    {  60,  78, 10 },   // AGACHADO
    {  79,  87, 20 },   // ATAQUE_AGACHADO
    {  88,  96, 20 }   // ATAQUE_SALTO
};
/*------------------------------------------------------------------------------
	CPersonaje: Constructor.
------------------------------------------------------------------------------*/
CPersonaje::CPersonaje()
{
	m_Estado=ESTADO_PJ_NORMAL;	
	m_uiAnimIni=mis_animlist[m_Estado].first_frame;
	m_uiAnimFin=mis_animlist[m_Estado].last_frame;
	m_uiFrameActual=mis_animlist[m_Estado].first_frame;
	m_bPisandoSuelo=FALSE;
	m_bControlado=FALSE;
	m_bVivo=TRUE;
	
	m_fVelocX=0.0;
	m_fVelocY=0.0;
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
CPersonaje::CPersonaje(const char * szFile)
{
	m_Estado=ESTADO_PJ_NORMAL;
}

/*------------------------------------------------------------------------------
	~CPersonaje:Destructor.
------------------------------------------------------------------------------*/
CPersonaje::~CPersonaje()
{
}
/*------------------------------------------------------------------------------
	Liberar: Libera los recursos.
------------------------------------------------------------------------------*/
void CPersonaje::Liberar()
{
	CEntidad::Liberar();
}

/*------------------------------------------------------------------------------
	Dibujar: Renderiza el personaje en el frame actual (utiliza el dibujar
	de la clase Entidad).
------------------------------------------------------------------------------*/
void CPersonaje::Dibujar(unsigned int uiFrame)
{	
	CEntidad::Dibujar(uiFrame);	
}

/*------------------------------------------------------------------------------
	Actualizar: Actualiza la posicion, animación, estado,etc... del personaje
	en función de los atributos de la clase.
------------------------------------------------------------------------------*/
void CPersonaje::Actualizar()
{	
	switch(getEstado())
	{
		//--------------------------------------
		case ESTADO_PJ_NORMAL:			
		case ESTADO_PJ_CORRER:		
		case ESTADO_PJ_AGACHADO:			
			if(!EnElSuelo())
				HacerCaer();			
		break;
		//--------------------------------------
		case ESTADO_PJ_SALTO:
			if(getVelocY()<(-0.07))
				setVelocY(-0.07);	
							
			setVelocY(getVelocY()+GRAVEDAD);			
			
			if(EnElSuelo() && getVelocY()<-0.005)
			{
				setVelocY(0);
				setVelocX(0);
				setY(getYCelda()-getMinY()-0.005);
				setEstado(ESTADO_PJ_NORMAL);
			}
		break;
		//--------------------------------------
		case ESTADO_PJ_ATAQUE:		
			if((getFrameActual())>=getAnimFin())
	   			setEstado(ESTADO_PJ_NORMAL);
		break;			
		//--------------------------------------
		case ESTADO_PJ_ATAQUE_AGACHADO:
			if((getFrameActual())>=getAnimFin())
	   			setEstado(ESTADO_PJ_AGACHADO);
		break;			
		//--------------------------------------
		case ESTADO_PJ_ATAQUE_SALTO:
		
			if((getFrameActual())>=getAnimFin())
	   			setEstado(ESTADO_PJ_SALTO);
	   			
	   		if(getVelocY()<(-0.07))
				setVelocY(-0.07);	
							
			setVelocY(getVelocY()+GRAVEDAD);			
			
			if(EnElSuelo() && getVelocY()<-0.005)
			{
				setVelocY(0);
				setVelocX(0);
				setY(getYCelda()-getMinY()-0.005);
				setEstado(ESTADO_PJ_NORMAL);
			}
		break;	
		//--------------------------------------
		default:			
		break;
	}	

	
	/* 
		Medida de Seguridad
		Comprobamos si el personaje está "dentro" de un bloque de escenario
		por algún tipo de error. Si es asi lo sacamos del mismo.
	*/
	int yc=getEscenario()->f2celdaY(getY()+getMinY());
	int xc=getEscenario()->f2celdaX(getX());	
	
	if(getEscenario()->EsSuelo(xc,yc))	
		setY(getY()+(LARGO_BLOQUE));

	/* 
		Esta dentro de los limites del escenario?
	*/
	if(getX()<=0.12)
	{
			setVelocX(0);
			setX(0.12001);
	}	

	float endesc=((getEscenario()->getLargo()-1)*LARGO_BLOQUE);
	if(getX()>endesc)
	{
		setVelocX(0);
		setX(endesc);
	}

	
	/*
		Se choca con alguna pared?
	*/
	float d;	
	d=getDistanciaPared();	
	
	if(d<0.03)
	{
		setVelocX(0);
	}
	
	
	
	/*
		Actualizamos la posicion y dibujamos
	*/
	setY(getY()+getVelocY());	
	setX(getX()+getVelocX());
	
	//if(m_Estado!=ESTADO_PJ_TIESO)
		ActualizarFrame();	        
    
	Dibujar(m_uiFrameActual);
}
/*------------------------------------------------------------------------------
	ActualizarFrame: Avanza la animación actual. Se encarga de que algunas
	animaciones especiales (Salto o disparo) se ejecuten correctamente.
------------------------------------------------------------------------------*/
void CPersonaje::ActualizarFrame()
{	
	
	unsigned int frametime=m_Tiempo.CurrentTime();
	float fps=(ANIM_TEMPO/mis_animlist[m_Estado].fps);
	
	if((frametime>fps 							|| 
		m_uiFrameActual==FRAME_DISPARO 			|| 
		m_uiFrameActual==FRAME_DISPARO_AGACHADO || 
		m_uiFrameActual==FRAME_DISPARO_SALTO) 	&&
		m_uiFrameActual!=FRAME_FIN_SALTO)
	{			
		m_uiFrameActual++;		
		m_Tiempo.Resetear();
	}
	
	if((m_uiFrameActual)>m_uiAnimFin)
    	m_uiFrameActual=m_uiAnimIni;
}

/*------------------------------------------------------------------------------
	setEstado: Cambia el estado del personaje, cambiando a su vez los atributos
	que controlan la animación.
------------------------------------------------------------------------------*/
void CPersonaje::setEstado(EstadoPersonaje Estado)
{
	m_Estado=Estado;
	m_uiAnimIni=mis_animlist[m_Estado].first_frame;
	m_uiAnimFin=mis_animlist[m_Estado].last_frame;
	m_uiFrameActual=mis_animlist[m_Estado].first_frame;

}

/*------------------------------------------------------------------------------
	EnElSuelo:Retorna TRUE si el personaje "toca" suelo. Sirve para parar al
	personaje cuando está cayendo y establecer si el personaje está en el
	aire.
------------------------------------------------------------------------------*/
Bool CPersonaje::EnElSuelo()
{
	if(((getDistanciaSuelo()+m_fVelocY)>=-0.03 && (getDistanciaSuelo()+m_fVelocY<0.03)) || getY()<=-1)
		return TRUE;
	
	return FALSE;
}

/*------------------------------------------------------------------------------
	HacerCaer:Hace que el personaje "caiga", es decir, cambia al estado
	SALTO y establece el frame medio de la animación.
------------------------------------------------------------------------------*/
void CPersonaje::HacerCaer()
{
	m_uiFrameActual=68;
	setVelocY(-0.001);
	setEstado(ESTADO_PJ_SALTO);
}

/*------------------------------------------------------------------------------
	BajoPlataforma:Retorna TRUE si el personaje tiene una plataforma justo
	sobre el.
------------------------------------------------------------------------------*/
Bool CPersonaje::BajoPlataforma()
{
	int celdax,celday,celdainic;
	
	celdax=getEscenario()->f2celdaX(getX());
	celday=getEscenario()->f2celdaY(getY()+getMinY())-1;
	celdainic=celday;
			
	while(celday>=(celdainic-3))
	{		
		if(getEscenario()->getCelda(celday,celdax)!=-1)
		{			
			return TRUE;
		}		
		celday--;
	}			
	return FALSE;	
}

/*------------------------------------------------------------------------------
	SobrePlataforma: Devuelve TRUE si el personaje está "subido" en una
	plataforma (en lugar de en el suelo).
------------------------------------------------------------------------------*/
Bool CPersonaje::SobrePlataforma()
{
	int celdax,celday;
	Bool fin=FALSE;
	
	celdax=getEscenario()->f2celdaX(getX());
	celday=getEscenario()->f2celdaY(getY()+getMinY())+1;	
			
	while (!fin)
	{			
		if(getEscenario()->getCelda(celday,celdax)==-1)
		{			
			return TRUE;
		}		
		celday++;
		if(celday>=MAX_ALTURA_BLOQUES)	
			fin=TRUE;
	}			
	return FALSE;	
}

/*------------------------------------------------------------------------------
	SiguientePasoVacio:Retorna TRUE si el siguiente paso del personaje va a ser
	al vacío, es decir, va a caer de una plataforma.
------------------------------------------------------------------------------*/
Bool CPersonaje::SiguientePasoVacio()
{
	int celdax,celday;
	celdax=getEscenario()->f2celdaX(getX()+getVelocX());
	celday=getEscenario()->f2celdaY(getY()+getMinY())+1;	
			
	if(getEscenario()->getCelda(celday,celdax)==-1)				
		return TRUE;
		
	return FALSE;
}

